﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
namespace KingOfCSharp.iHunter.UI
{
    public class TaskCompleteEventArgs : EventArgs
    {
        public TaskItem Item { get; private set; }
        public TaskCompleteEventArgs(TaskItem item)
        {
            Item = item;
        }

    }


    public delegate void TaskCompleteEventHandler(object sender, TaskCompleteEventArgs e);

    public class TaskRunner : IDisposable
    {
        public TaskRunner(LocalClient client)
        {
            if (client == null)
                throw new ArgumentNullException();

            this.client = client;
            reqAvail = new AutoResetEvent(false);
            Tasks = new Queue<TaskItem>();

            worker = new Thread(new ThreadStart(WorkingThread));
            worker.IsBackground = true;
            worker.Start();

        }

        private LocalClient client;
        public Queue<TaskItem> Tasks { get; private set; }
        private AutoResetEvent reqAvail;

        Thread worker;

        public int TaskCount
        {
            get
            {
                Monitor.Enter(Tasks);
                int c = Tasks.Count;
                Monitor.Exit(Tasks);
                return c;
               
            }
        }
        public string[] GetTaskInfos()
        {
            List<string> infos = new List<string>();
            //try
            //{
                Monitor.Enter(Tasks);
                foreach (TaskItem item in Tasks)
                {
                    switch(item.Type)   
                    {
                        case TaskType.DownloadAttachment:
                            infos.Add(string.Format("Download attachment {0}",item.Attachments[0].FileName));
                            break;
                        case TaskType.SynchronizeAll:
                            infos.Add("Synchronize all channels ... ");
                            break;
                        case TaskType.SynchronizeChannel:
                            {
                                ChannelInfo info = client.GetChannelInfo(item.ChannelGuid);
                                if (info.Guid == Guid.Empty)
                                    infos.Add("Synchronize channel (unknown)");
                                else
                                    infos.Add(string.Format("Download attachment {0}", info.Name));
                            }
                            break;
                        case TaskType.SynchronizeFolder:
                            {
                                IFolder f = client.FindFolderByGuid(item.FolderGuid);
                                if (f == null)
                                    infos.Add("Synchronize folder (unknown)");
                                else
                                    infos.Add(string.Format("Synchronizing folder {0}", f.Name));
                            }
                            break;
                        case TaskType.SynchronizeMessages:
                            infos.Add(string.Format("Synchronize message {0}.",item.Messages[0].Title));
                            break;
                        default:
                            break;
                    }
                }
            //}
            //catch
            //{
                
            //}
            //finally
            //{
                Monitor.Exit(Tasks);
            //}
            return infos.ToArray();
        }
        public void EnqueueItem(TaskItem item)
        {
            Monitor.Enter(Tasks);
            try
            {
                if ((worker.ThreadState & ThreadState.Aborted) != 0 
                    || (worker.ThreadState & ThreadState.AbortRequested ) != 0
                    || (worker.ThreadState & ThreadState.StopRequested) != 0
                    || (worker.ThreadState & ThreadState.Stopped) != 0
                    )
                {
                    worker = new Thread(new ThreadStart(WorkingThread));
                    worker.IsBackground = true;
                    worker.Start();
                }
                Tasks.Enqueue(item);
                reqAvail.Set();
            }
            catch
            {
            }
            finally
            {
                Monitor.Exit(Tasks);
            }
        }

        public void CancelAll()
        {
            Tasks.Clear();
            Tasks = new Queue<TaskItem>();

            Thread t = new Thread(new ParameterizedThreadStart(
                delegate
                {
                    client.CancelBlockingCall();
                    worker.Join();
                }));
            t.Start();

            try
            {
                if (!t.Join(3000))
                {
                    try
                    {
                        worker.Abort();
                    }
                    catch
                    {
                    }
                    try
                    {
                        worker.Interrupt();
                    }
                    catch
                    {
                    }
                    try
                    {
                        t.Abort();
                    }
                    catch
                    {
                    }
                    try
                    {
                        t.Interrupt();
                    }
                    catch
                    {
                    }
                    return;
                }
            }
            catch (ThreadStartException)
            {
                return;
            }
            finally
            {
                OnTaskComplete(null);
            }
        }

        private void DispatchTask(TaskItem item)
        {
            //try
            //{
                switch (item.Type)
                {
                    case TaskType.DownloadAttachment:
                        client.DownloadAttachment(item.Attachments[0].Guid);
                        break;
                    case TaskType.SynchronizeAll:
                        client.SynchronizeAll();
                        break;
                    case TaskType.SynchronizeChannel:
                        client.SynchronizeChannel(item.ChannelGuid);
                        break;
                    case TaskType.SynchronizeFolder:
                        client.SynchronizeFolder(item.FolderGuid);
                        break;
                    case TaskType.SynchronizeMessages:
                        client.SynchronizeMessage(item.Messages[0].Guid);
                        break;
                    default:
                        break;
                }
            //}
            //catch
            //{
              
            //}
        }

        private void DownloadAttachments(TaskItem item)
        {
            foreach (IAttachment attachment in item.Attachments)
            {
                Attachment temp = new Attachment(attachment.Guid, attachment);
                   
                //TODO: Download attachment
                
            }

        }
        private void WorkingThread()
        {
            while (true)
            {
                TaskItem item = null;

                Monitor.Enter(Tasks);
                while (Tasks.Count == 0)
                {
                    Monitor.Exit(Tasks);
                    reqAvail.WaitOne();
                    Monitor.Enter(Tasks);
                }
                if (Tasks.Count > 0)
                    item = Tasks.Peek();
                Monitor.Exit(Tasks);


                DispatchTask(item);

                Monitor.Enter(Tasks);
                if (Tasks.Count > 0)
                    Tasks.Dequeue();

                Monitor.Exit(Tasks);

                OnTaskComplete(item);
            }
        }
        protected void OnTaskComplete(TaskItem item)
        {
            if (TaskComplete != null)
            {
                TaskComplete(this, new TaskCompleteEventArgs(item));
            }
        }
        public event TaskCompleteEventHandler TaskComplete;

        #region IDisposable 成员

        public void Dispose()
        {
            CancelAll();
        }

        #endregion
    }
}
